package com.moli.iov.admin.websocket.handle;

import com.moli.iov.admin.model.dto.WebSocketDto;
import com.moli.iov.admin.mq.activemq.ActiveMQProducer;
import com.moli.iov.admin.websocket.facotry.WebSocketQueryServiceFactory;
import com.moli.iov.admin.websocket.facotry.WebSocketSingleExecuteServiceFactory;
import com.moli.iov.admin.websocket.service.WebSocketQueryService;
import com.moli.iov.admin.websocket.service.WebSocketSingleExecuteService;
import com.moli.iov.admin.websocket.utils.MessageUtils;
import com.moli.iov.admin.websocket.utils.WebSocketContant;
import com.moli.iov.util.GsonUtil;
import com.moli.iov.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @ClassName WebSocketBizHandler
 * @Description WebSocket业务处理类
 * @Author 李伟松
 * @CreateDate 2019-03-06 下午 3:46
 * @UpdateDate 2019-03-06 下午 3:46
 * @Version 1.0
 */
@Slf4j
@Component
public class WebSocketBizHandler {

    @Resource
    ActiveMQProducer activeMQProducer;

    private static final Map<String, WsSession> sessions = new ConcurrentHashMap<>();

    public void remove(String id) {
        sessions.remove(id);
    }

    class WsSession {

        public WsSession(WebSocketSession session, WebSocketDto webSocketDto) {
            this.webSocketDto = (webSocketDto == null ? new WebSocketDto() : webSocketDto);
            this.webSocketSession = session;
        }

        WebSocketSession webSocketSession;
        WebSocketDto webSocketDto;

        public WebSocketDto getWebSocketDto() {
            return webSocketDto;
        }

        public WebSocketSession getSession() {
            return webSocketSession;
        }
    }


    public static void main(String[] args) {
        WebSocketDto webSocketDto = new WebSocketDto();
        webSocketDto.setEnable(true);
        webSocketDto.setMethod(WebSocketContant.VEHICLEMONITOR_DETAIL);
        webSocketDto.setParam("LNBSCB3F9JW186800");
        String s = JsonUtils.toJson(webSocketDto);
        System.out.println(s);
    }

    public void handle(String message, WebSocketSession session) {
        WebSocketDto webSocketDto = GsonUtil.parseJsonWithGson(message, WebSocketDto.class);

        if (webSocketDto == null) {
            sendMess(MessageUtils.error("websocket参数为null"), session);
        }

        if (webSocketDto.getTimer() == null || webSocketDto.getTimer() < 5000L) {
            webSocketDto.setTimer(10000L);
        }

        webSocketDto.setSessionId(session.getId());
        webSocketDto.setRequestTime(System.currentTimeMillis());

        //本地存储链接和参数
        sessions.put(session.getId(), new WsSession(session, webSocketDto));

        try {
            if (StringUtils.isEmpty(webSocketDto.getMethod())
                    || webSocketDto.getParam() == null
                    || webSocketDto.getTimer() == null
                    || (!WebSocketContant.contains(webSocketDto.getMethod()))) {
                log.error("参数校验失败，{}",webSocketDto);
                sendMess(MessageUtils.error("参数校验失败"), session);
                return;
            }

            //发送消息和任务
            send(webSocketDto);

            //收到消息时执行一次
            WebSocketSingleExecuteService webSocketSingleExecuteService = WebSocketSingleExecuteServiceFactory.getService(webSocketDto.getMethod());
            if(webSocketSingleExecuteService!=null){
                webSocketSingleExecuteService.execute(JsonUtils.toJson(webSocketDto.getParam()));
            }


        } catch (Exception e) {
            log.error("[websocket][handleTextMessage][异常：{}]", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * @Param: [webSocketDto]
     * @Return: void
     * @Description 给前端返回信息，并添加延迟队列。
     * @Author 李伟松
     * @CreateDate 2019-03-06 下午 4:54
     */
    public void send(WebSocketDto webSocketDto) throws Exception {

        WsSession wss = sessions.get(webSocketDto.getSessionId());
        if (wss == null) {
            return;
        }
        if (wss.getWebSocketDto() == null || wss.getWebSocketDto().getEnable() == null || !wss.getWebSocketDto().getEnable()) {
            log.info("[send][停止推送][method:{}]", wss.getWebSocketDto().getMethod());
        }

        WebSocketDto webSocketDtoNew = webSocketDto;
        WebSocketDto webSocketDtoOld = wss.getWebSocketDto();

        if ((WebSocketContant.checkGroup(webSocketDtoNew.getMethod(), webSocketDtoOld.getMethod()))
                || (webSocketDtoNew.getMethod().equals(webSocketDtoOld.getMethod()))
                && webSocketDtoNew.getTimer().equals(webSocketDtoOld.getTimer())
                && webSocketDtoNew.getRequestTime().equals(webSocketDtoOld.getRequestTime())) {

            //请求服务接口返回数据给前端
            WebSocketQueryService service = WebSocketQueryServiceFactory.getService(webSocketDto.getMethod());
            if (service != null) {
                String body = service.query(JsonUtils.toJson(webSocketDto.getParam()),webSocketDto.getToken());
                sendMess(body, wss.getSession());

                //加入队列，提供订阅
                activeMQProducer.send(webSocketDto);
            }

        }
    }

    /**
     * 查询接口返回字符串，并发送给前端
     */
    private void sendMess(String body, WebSocketSession session) {
        if (session != null && !StringUtils.isEmpty(body)) {
            //body通过查询服务获得
            try {
                TextMessage message = new TextMessage(body);
                if (session.isOpen()) {
                    session.sendMessage(message);
                }
            } catch (Exception e) {
                //执行方法异常
                log.error("[websocket][sendMessage][发送失败][{}]", e.getMessage());
                e.printStackTrace();
                return;
            }
        }
    }
}
